package ita.class1.group2.supermarket.common.jms;

import ita.class1.group2.supermarket.common.annotation.Autowired;
import ita.class1.group2.supermarket.common.annotation.Component;
import ita.class1.group2.supermarket.common.captain.CaptainApplication;
import ita.class1.group2.supermarket.common.captain.model.JmsConfiguration;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.log4j.Logger;
import javax.jms.*;
import java.util.HashMap;
import java.util.Map;

@Component
public class JmsReceiver {

    private static final Logger LOGGER = Logger.getLogger(JmsReceiver.class);

    @Autowired private JmsManager jmsManager;

    private Map<String, Connection> connectionMap = null;
    private Map<String, Session> sessionMap = null;
    private Map<String, MessageConsumer> messageConsumerMap = null;

    /**
     * must invoke after server start
     */
    public void initializeAllReceiver() {
        LOGGER.info("Initialize JMS receiver");
        this.connectionMap = new HashMap<String, Connection>();
        this.sessionMap = new HashMap<String, Session>();
        this.messageConsumerMap = new HashMap<String, MessageConsumer>();
        for (JmsConfiguration configuration: jmsManager.getJmsConfigurations()) {
            LOGGER.info("Create JMS connection: " + configuration.getUrl());
            Connection connection = jmsManager.getConnection(configuration.getUrl());
            this.connectionMap.put(configuration.getUrl(), connection);
            for (String queueName: configuration.getQueueNames()) {
                try {
                    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                    this.sessionMap.put(configuration.getUrl() + "/" + queueName, session);
                    this.messageConsumerMap.put(configuration.getUrl() + "/" + queueName, session.createConsumer(new ActiveMQQueue(queueName)));
                    LOGGER.info("Create JMS session and consumer: " + queueName + " @ " + configuration.getUrl());
                } catch (JMSException e) {
                    LOGGER.error("Can not create JMS session: " + queueName + " @ " + configuration.getUrl());
                    e.printStackTrace();
                }
            }
        }
    }

    public void startReceiver() {
        for (JmsConfiguration configuration: jmsManager.getJmsConfigurations()) {
            for (String queueName: configuration.getQueueNames()) {
                String consumerKey = configuration.getUrl() + "/" + queueName;
                try {
                    LOGGER.info("Set JMS message listener: " + consumerKey);
                    MessageListener messageListener = (MessageListener)CaptainApplication.getInstance().getComponentManager().getBean(Class.forName(configuration.getListeners().get(configuration.getQueueNames().indexOf(queueName))));
                    this.messageConsumerMap.get(consumerKey).setMessageListener(messageListener);
                    LOGGER.info("Start jms connection: " + configuration.getUrl());
                    this.connectionMap.get(configuration.getUrl()).start();
                } catch (Exception e) {
                    LOGGER.info("Can not start jms receiver: " + consumerKey +", Message: " + e.toString());
                }
            }
        }
    }

    public void stopReceiver() {
        for (JmsConfiguration configuration: jmsManager.getJmsConfigurations()) {
            for (String queueName: configuration.getQueueNames()) {
                try {
                    String consumerKey = configuration.getUrl() + "/" + queueName;
                    this.messageConsumerMap.get(consumerKey).close();
                    LOGGER.info("Stop jms message listener: " + consumerKey);
                } catch (Exception e) {
                    LOGGER.error("Can not stop jms message listener, Message: " + e.toString());
                }
            }
        }
    }

    public void destroy() {
        for (JmsConfiguration configuration: jmsManager.getJmsConfigurations()) {
            for (String queueName: configuration.getQueueNames()) {
                String key = configuration.getUrl() + "/" + queueName;
                if (this.sessionMap.containsKey(key)) {
                    try {
                        this.sessionMap.get(key).close();
                        LOGGER.info("Close jms session: " + key);
                    } catch (JMSException e) {
                        LOGGER.error("Can not close jms session: " + key + ", Message: " + e.toString());
                    }
                }
            }
            if (this.connectionMap.containsKey(configuration.getUrl())) {
                try {
                    this.connectionMap.get(configuration.getUrl()).close();
                    LOGGER.info("Close jms connection: " + configuration.getUrl());
                } catch (JMSException e) {
                    LOGGER.error("Can not close jms connection: " + configuration.getUrl() + ", Message: " + e.toString());
                }
            }
        }
    }

    /**
     * for unit test
     * @return consumers map
     */
    public Map<String, MessageConsumer> getMessageConsumerMap() {
        return messageConsumerMap;
    }

    /**
     * for unit test
     * @param jmsManager
     */
    public void setJmsManager(JmsManager jmsManager) {
        this.jmsManager = jmsManager;
    }
}
